import Ids from 'ids';
import {getBusinessObject, is} from 'bpmn-js/lib/util/ModelUtil';
import {isAny} from "bpmn-js/lib/features/modeling/util/ModelingUtil";
import {isArray, without} from 'min-dash';
import {useService} from "bpmn-js-properties-panel";
import {CheckboxEntry, SelectEntry, TextAreaEntry, TextFieldEntry} from "@bpmn-io/properties-panel";
import {jsx} from "@bpmn-io/properties-panel/preact/jsx-runtime";
import Constants from "@/components/business/constants";

export function getExtension(element, type) {
  if (!element.extensionElements) {
    return null;
  }

  return element.extensionElements.values.filter(function(e) {
    return e.$instanceOf(type);
  })[0];
}

export function getListenersContainer(element) {
  const businessObject = getBusinessObject(element);
  return businessObject.get('processRef') || businessObject;
}

export function createElement(elementType, properties, parent, factory) {
  const element = factory.create(elementType, properties);

  if (parent) {
    element.$parent = parent;
  }

  return element;
}

export function nextId(prefix) {
  const ids = new Ids([ 32,32,1 ]);

  return ids.nextPrefixed(prefix);
}

export function getScriptType(element) {
  const businessObject = getBusinessObject(element);
  const scriptValue = getScriptValue(businessObject);
  if (typeof scriptValue !== 'undefined') {
    return 'script';
  }
  const resource = businessObject.get('activiti:resource');
  if (typeof resource !== 'undefined') {
    return 'resource';
  }
}
export function getScriptValue(businessObject) {
  return businessObject.get(getScriptProperty(businessObject));
}
export function isScript$2(element) {
  return is(element, 'activiti:Script');
}
export function getScriptProperty(businessObject) {
  return isScript$2(businessObject) ? 'value' : 'script';
}
export function isInterrupting(element) {
  return element && getBusinessObject(element).isInterrupting !== false;
}

export function getRelevantBusinessObject(element) {
  let businessObject = getBusinessObject(element);
  if (is(element, 'bpmn:Participant')) {
    return businessObject.get('processRef');
  }
  return businessObject;
}

export function getPropertyName(namespace = 'camunda') {
  if (namespace === 'zeebe') {
    return 'properties';
  }
  return 'values';
}

export function getExtensionElementsAndName(businessObject, type = undefined,name = undefined) {
  if(businessObject==undefined){
    return [];
  }
  const extensionElements = businessObject.get('extensionElements');
  if (!extensionElements) {
    return [];
  }
  let values = extensionElements.get('values');
  if (!values || !values.length) {
    return [];
  }
  if (type) {
    values = values.filter(value => is(value, type));
  }
  if(name) {
    values = values.filter(value => value.get('name')==name);
  }
  return values;
}


export function getExtensionElementsList(businessObject, type = undefined) {
  if(businessObject==undefined){
    return [];
  }
  const extensionElements = businessObject.get('extensionElements');
  if (!extensionElements) {
    return [];
  }
  const values = extensionElements.get('values');
  if (!values || !values.length) {
    return [];
  }
  if (type) {
    return values.filter(value => is(value, type));
  }
  return values;
}

export function getProperties(element, namespace = 'activiti') {
  const businessObject = getRelevantBusinessObject(element);
  return getExtensionElementsList(businessObject, `${namespace}:Properties`)[0];
}
export function getPropertiesList(element, namespace = 'activiti') {
  const businessObject = getRelevantBusinessObject(element);
  const properties = getProperties(businessObject, namespace);
  return properties && properties.get(getPropertyName(namespace));
}

export function getListenerBusinessObject(businessObject) {
  if (isAny(businessObject, ['activiti:ExecutionListener', 'activiti:TaskListener'])) {
    return businessObject;
  }
}
export function getImplementationType(element) {
  const businessObject = getListenerBusinessObject(element);
  if (!businessObject) {
    return;
  }
  const cls = businessObject.get('activiti:class');
  if (typeof cls !== 'undefined') {
    return 'class';
  }
  const expression = businessObject.get('activiti:expression');
  if (typeof expression !== 'undefined') {
    return 'expression';
  }
  const delegateExpression = businessObject.get('activiti:delegateExpression');
  if (typeof delegateExpression !== 'undefined') {
    return 'delegateExpression';
  }
  const script = businessObject.get('script');
  if (typeof script !== 'undefined') {
    return 'script';
  }
}
export function removeListenerFactory({ commandStack, element, listener, type }) {
  return function(event) {
    event.stopPropagation();
    // 'activiti:ExecutionListener'
    let businessObject = getBusinessObject(element)
    const extensionElements = businessObject.extensionElements;
    if (!extensionElements) {
      return;
    }
    const parameters = without(extensionElements.get('values'), listener);
    commandStack.execute('element.updateModdleProperties', {
      element,
      moddleElement: extensionElements,
      properties: {
        values: parameters
      }
    });
  };
}
export function addListenerFactory({ element, bpmnFactory, commandStack, type }) {
  return function(event) {
    event.stopPropagation();
    const commands = [];
    const businessObject = getBusinessObject(element);
    let extensionElements = businessObject.get('extensionElements');

    if (!extensionElements) {
      extensionElements = createElement(
          'bpmn:ExtensionElements',
          { values: [] },
          businessObject,
          bpmnFactory
      );

      commands.push({
        cmd: 'element.updateModdleProperties',
        context: {
          element,
          moddleElement: businessObject,
          properties: { extensionElements }
        }
      });
    }
    // 'activiti:ExecutionListener'
    const newListener = createElement(type, {
      name: nextId('exec_lis_'),
      value: ''
    }, extensionElements, bpmnFactory);

    commands.push({
      cmd: 'element.updateModdleProperties',
      context: {
        element,
        moddleElement: extensionElements,
        properties: {
          values: [ ...extensionElements.get('values'), newListener ]
        }
      }
    });
    commandStack.execute('properties-panel.multi-command-executor', commands);
  };
}


export function implementationDetails(element,id,register,translate,listener,list) {
  const type = getImplementationType(listener)
  let component=[];
  if (type === 'class') {
    component.push(register.findEntries('javaClass',translate))
  }else if (type === 'expression') {
    component.push(register.findEntries('listenerExpression',translate))
    component.push(register.findEntries('listenerResultVariable',translate))
  }else if (type === 'delegateExpression') {
    component.push(register.findEntries('delegateExpression',translate))
  }else if (type === 'script') {
    scriptProps(element,id,register,translate,listener,component)
  }
  component.push(register.findEntries('fields',translate))
  if(component){
    for (let i = 0; i < component.length; i++) {
      let temp = {...component[i]}
      if(type){
        temp.id = id+"-"+type
      }else{
        temp.id = id+"-"+component[i].id
      }
      temp.businessObject =listener;
      temp.idPrefix = temp.id
      temp.script = listener.get('script')
      temp.element=element
      temp.listener=listener
      temp.register=register
      list.push(temp)
    }
  }
}

export function scriptProps(element,id,register,translate,listener,component) {
  const scriptType = getScriptType(listener.get('script'));
  component.push(register.findEntries('format',translate))
  component.push(register.findEntries('scriptType',translate))
  if (scriptType === 'script') {
    component.push(register.findEntries('script',translate))
  }
  if (scriptType === 'resource') {
    component.push(register.findEntries('resource',translate))
  }
}
/**
 * 更新多实例的数据
 * @param element
 * @param businessObject
 * @param bpmnFactory
 * @param commandStack
 * @param props   multiInstanceLoopCharacteristics属性
 * @param bodyElementName   multiInstanceLoopCharacteristics子元素名称
 * @param body  multiInstanceLoopCharacteristics子元素的body内容
 */
export function updateMultiInstance(element,businessObject,bpmnFactory,commandStack,props,bodyElementName,body) {
  const commands = [];
  let loopCharacteristics = businessObject.get('loopCharacteristics');

  // 创建multiInstanceLoopCharacteristics
  if (!loopCharacteristics) {
    loopCharacteristics = createElement(
        'bpmn:MultiInstanceLoopCharacteristics',
        {...props},
        businessObject,
        bpmnFactory
    );

    commands.push({
      cmd: 'element.updateModdleProperties',
      context: {
        element,
        moddleElement: businessObject,
        properties: { loopCharacteristics }
      }
    });
  }
  // 创建loopCharacteristics的子元素
  if(bodyElementName) {
    let values =loopCharacteristics.get('values')
    if (values && values.length>0) {
      values = values.filter(value => is(value, bodyElementName));
    }
    // 创建元素
    if (!values || !values.length) {
      let temp = createElement(
          'bpmn:FormalExpression',
          body,
          loopCharacteristics,
          bpmnFactory
      );
      let properties = {}
      properties[bodyElementName] = temp;
      commands.push({
        cmd: 'element.updateModdleProperties',
        context: {
          element,
          moddleElement: loopCharacteristics,
          properties
        }
      });
    }
  }

  commands.push({
    cmd: 'element.updateModdleProperties',
    context: {
      element,
      moddleElement: loopCharacteristics,
      properties: props
    }
  });
  commandStack.execute('properties-panel.multi-command-executor', commands);
}
export function addMultiInstanceFactory({ element, bpmnFactory, commandStack }) {
  return function(event) {
    event.stopPropagation();
    const commands = [];
    const businessObject = getBusinessObject(element);
    let loopCharacteristics = businessObject.get('loopCharacteristics');

    if (!loopCharacteristics) {
      loopCharacteristics = createElement(
          'bpmn:MultiInstanceLoopCharacteristics',
          { values: [] },
          businessObject,
          bpmnFactory
      );

      commands.push({
        cmd: 'element.updateModdleProperties',
        context: {
          element,
          moddleElement: businessObject,
          properties: { loopCharacteristics }
        }
      });
    }
    commandStack.execute('properties-panel.multi-command-executor', commands);
  };
}
export function removeMultiInstanceFactory({ commandStack, element, loopCharacteristics }) {
  return function(event) {
    event.stopPropagation();
    const businessObject = getBusinessObject(element);
    commandStack.execute('element.updateModdleProperties', {
      element,
      moddleElement: businessObject,
      properties: {
        loopCharacteristics: undefined
      }
    });
  };
}
export function getLoopCharacteristics(businessObject) {
  if(businessObject==undefined){
    return businessObject;
  }
  const loopCharacteristics = businessObject.get('loopCharacteristics');
  if (loopCharacteristics) {
    return loopCharacteristics;
  }
}
export function getLoopCharacteristicsList(businessObject, type = undefined) {
  if(businessObject==undefined){
    return [];
  }
  const loopCharacteristics = businessObject.get('loopCharacteristics');
  if (!loopCharacteristics) {
    return [];
  }
  const values = loopCharacteristics.get('values');
  if (!values || !values.length) {
    return [];
  }
  if (type) {
    return values.filter(value => is(value, type));
  }
  return values;
}
export function removeExtensionElements(element, businessObject, extensionElementsToRemove, commandStack) {
  if (!isArray(extensionElementsToRemove)) {
    extensionElementsToRemove = [extensionElementsToRemove];
  }
  const extensionElements = businessObject.get('extensionElements'),
      values = extensionElements.get('values').filter(value => !extensionElementsToRemove.includes(value));
  commandStack.execute('element.updateModdleProperties', {
    element,
    moddleElement: extensionElements,
    properties: {
      values
    }
  });
}
export function addExtensionElements(element, businessObject, extensionElementToAdd, bpmnFactory, commandStack) {
  const commands = [];
  let extensionElements = businessObject.get('extensionElements');

  // (1) create bpmn:ExtensionElements if it doesn't exist
  if (!extensionElements) {
    extensionElements = createElement('bpmn:ExtensionElements', {
      values: []
    }, businessObject, bpmnFactory);
    commands.push({
      cmd: 'element.updateModdleProperties',
      context: {
        element,
        moddleElement: businessObject,
        properties: {
          extensionElements
        }
      }
    });
  }
  extensionElementToAdd.$parent = extensionElements;

  // (2) add extension element to list
  commands.push({
    cmd: 'element.updateModdleProperties',
    context: {
      element,
      moddleElement: extensionElements,
      properties: {
        values: [...extensionElements.get('values'), extensionElementToAdd]
      }
    }
  });
  commandStack.execute('properties-panel.multi-command-executor', commands);
}
// 构建开关的字段
export function CheckboxProps(props) {
  const { element, id, filedName, filedType,label } = props;
  const commandStack = useService('commandStack');
  const bpmnFactory = useService('bpmnFactory');
  const modeling = useService('modeling');
  const translate = useService('translate');
  const debounce = useService('debounceInput');
  const businessObject = getBusinessObject(element)
  let extensionElementsTo = getExtensionElementsAndName(businessObject,'activiti:Field',filedName);
  let field;
  if(extensionElementsTo&&extensionElementsTo.length){
    field = extensionElementsTo[0]
  }
  const getValue = () => {
    let val = ''
    if(field) {
      val = field.string || field.stringValue || field.expression;
      if(val){
        val = Boolean(val)
      }
    }
    return val;
  }

  const setValue = value => {
    // 如果值不为空，元素不存在，创建
    if(value&&!field){
      field = createElement('activiti:Field', {name:filedName}, businessObject, bpmnFactory);
      addExtensionElements(element, businessObject, field, bpmnFactory, commandStack);
    }
    // 有值则更新
    if(value){
      let properties = {};
      properties[filedType] = ''+value
      return commandStack.execute('element.updateModdleProperties', {
        element,
        moddleElement: field,
        properties
      });
    }else {
      // 删除元素
      removeExtensionElements(element, businessObject, field, commandStack);
    }
  }
  return CheckboxEntry({
    element,
    id: id + '-' + filedName,
    label: label||translate(id),
    getValue,
    setValue,
    debounce
  });
}
// 构建邮件的各个字段
export function FieldProps(props) {
  const { element, id, filedName, filedType,label,placeholder,labelPostion } = props;
  const commandStack = useService('commandStack');
  const bpmnFactory = useService('bpmnFactory');
  const modeling = useService('modeling');
  const translate = useService('translate');
  const debounce = useService('debounceInput');
  const businessObject = getBusinessObject(element)
  let extensionElementsTo = getExtensionElementsAndName(businessObject,'activiti:Field',filedName);
  let field;
  if(extensionElementsTo&&extensionElementsTo.length){
    field = extensionElementsTo[0]
  }
  const getValue = () => {
    if(field) {
      return field.string || field.stringValue || field.expression;
    }
    return '';
  }

  const setValue = value => {
    // 如果值不为空，元素不存在，创建
    if(value&&!field){
      field = createElement('activiti:Field', {name:filedName}, businessObject, bpmnFactory);
      addExtensionElements(element, businessObject, field, bpmnFactory, commandStack);
    }
    // 有值则更新
    if(value){
      let properties = {};
      properties[filedType] = value
      return commandStack.execute('element.updateModdleProperties', {
        element,
        moddleElement: field,
        properties
      });
    }else {
      // 删除元素
      removeExtensionElements(element, businessObject, field, commandStack);
    }
  }
  if(filedName=='html'){
    return TextAreaEntry({
      element,
      id: id + '-'+filedName,
      label: label||translate(id),
      getValue,
      setValue,
      debounce,
      labelPostion,
      placeholder:translate(placeholder)
    });
  }else {
    return TextFieldEntry({
      element,
      id: id + '-' + filedName,
      label: label||translate(id),
      getValue,
      setValue,
      debounce,
      labelPostion,
      placeholder:translate(placeholder)
    });
  }
}
export function FieldCommonSelect(props) {
  const { element, id, filedName, filedType,getOptions,defaultValue,label} = props;
  const commandStack = useService('commandStack');
  const bpmnFactory = useService('bpmnFactory');
  const modeling = useService('modeling');
  const translate = useService('translate');
  const debounce = useService('debounceInput');
  const businessObject = getBusinessObject(element)
  let extensionElementsTo = getExtensionElementsAndName(businessObject,'activiti:Field',filedName);
  let field;
  if(extensionElementsTo&&extensionElementsTo.length){
    field = extensionElementsTo[0]
  }
  const getValue = () => {
    if(field) {
      let value = field.string || field.stringValue || field.expression;
      return value
    }
    return '';
  }

  const setValue = value => {
    // 如果值不为空，元素不存在，创建
    if(value&&!field){
      field = createElement('activiti:Field', {name:filedName}, businessObject, bpmnFactory);
      addExtensionElements(element, businessObject, field, bpmnFactory, commandStack);
    }
    // 有值则更新
    if(value){
      let properties = {};
      properties[filedType] = value
      return commandStack.execute('element.updateModdleProperties', {
        element,
        moddleElement: field,
        properties
      });
    }else {
      // 删除元素
      removeExtensionElements(element, businessObject, field, commandStack);
    }
  }
  const getOptionsFun = function (){
      return getOptions(translate)
  }
  return jsx(SelectEntry, {
    id: id,
    label: label||translate(id),
    getValue: getValue,
    setValue: setValue,
    defaultValue,
    getOptions: getOptionsFun
  });
}

export function getRootElement(element) {
  let parent = element;
  while (parent.parent && !is(parent, 'bpmn:Process')) {
    parent = parent.parent;
  }
  return parent;
}

/**
 * 获取根元素的字段列表
 * @param businessObject
 * @param type
 * @param prefix
 * @returns {*[]}
 */
export function getRootElementProperties(businessObject,name = 'hiss') {
  if(businessObject==undefined){
    return [];
  }
  let root = getRootElement(businessObject);
  let rootBusinessObject = getBusinessObject(root)
  const extensionElements = rootBusinessObject.get('extensionElements');
  if (!extensionElements) {
    return [];
  }
  const props = getPropertiesList(root)
  if (name&&props) {
    return props.filter(prop => isName(prop, name));
  }
  return [];
}

export function isName(element, name) {
  var bo = getBusinessObject(element);
  return bo && bo.get('name')==name
}


export function BusinessPeopleGroupProps(props) {
  const {
    id,element,injector,register,buttons,types
  } = props;
  if (!is(element, 'bpmn:UserTask')) {
    return;
  }
  const bpmnFactory = injector.get('bpmnFactory'),
      commandStack = injector.get('commandStack');
  const translate = injector.get('translate');
  const businessObject = getBusinessObject(element);
  let fieldType = getExtensionElementsAndName(businessObject,'activiti:Field',Constants.hissBusinessSingleUserType);
  if(fieldType&&fieldType.length){
    fieldType = fieldType[0].string || fieldType[0].stringValue || fieldType[0].expression;
  }
  const items = []
  items.push({
    id,
    label:"   ",
    entries: getBusinessPeopleEntries(element,id,register,translate,businessObject,fieldType,buttons,types),
    shouldOpen:true
  })
  return {
    items,
    shouldOpen:true
  };
}
function getBusinessPeopleEntries(element,id,register,translate,businessObject,fieldType,buttons,types){
  let arrs = types;
  if (fieldType&&(fieldType==Constants.values.singleUserTypeDesignatedUser
      ||fieldType==Constants.values.singleUserTypeDesignatedRole
      ||fieldType==Constants.values.singleUserTypeDesignatedDepartment
      ||fieldType==Constants.values.singleUserTypeOwnerSelect
  )){
    arrs.push('singleApproveDesignatedList')
  }
  for (let i = 0; i < buttons.length; i++) {
    arrs.push(buttons[i])
    let tempValue = getBusinessPeopleFieldValue(businessObject,buttons[i])
    if(tempValue=='true'){
      arrs.push(buttons[i]+'Text')
    }
  }
  const list = []
  for (let i = 0; i < arrs.length; i++) {
    let entries = register.findEntries(arrs[i],translate)
    entries = {...entries}
    entries.id = arrs[i];
    if(fieldType&&fieldType!=''&&arrs[i]=='singleApproveDesignatedList'){
      entries.label= translate(fieldType)+'范围'
    }
    list.push(entries)
  }
  return list
}
export function getBusinessPeopleFieldValue(businessObject,filedName){
  let extensionElementsTo = getExtensionElementsAndName(businessObject,'activiti:Field',filedName);
  let field;
  if(extensionElementsTo&&extensionElementsTo.length){
    field = extensionElementsTo[0]
  }
  if(field) {
    return  field.string || field.stringValue || field.expression;
  }
  return ''
}
